{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import random,datetime,functools,operator"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "geneset = [i +1 for i in range(10)]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Fitness:\n",
    "    def __init__(self, group1Sum, group2Product):\n",
    "        self.Group1Sum = group1Sum\n",
    "        self.Group2Product = group2Product\n",
    "        sumDifference = abs(36 - group1Sum)\n",
    "        productDifference = abs(360 - group2Product)\n",
    "        self.TotalDifference = sumDifference + productDifference\n",
    "\n",
    "    def __gt__(self, other):\n",
    "        return self.TotalDifference < other.TotalDifference\n",
    "\n",
    "    def __eq__(self,other):\n",
    "        return self.TotalDifference == other.TotalDifference\n",
    "\n",
    "    def __str__(self):\n",
    "        return \"sum: {} prod: {}\".format(self.Group1Sum,\n",
    "            self.Group2Product)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_fitness(genes):\n",
    "    group1Sum = sum(genes[0:5])\n",
    "    group2Product = functools.reduce(operator.mul, genes[5:10])\n",
    "    return Fitness(group1Sum, group2Product)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "def display(candidate, startTime):\n",
    "    timeDiff = datetime.datetime.now() - startTime\n",
    "    print(\"{} - {}\\t{}\\t{}\".format(\n",
    "        ', '.join(map(str, candidate.Genes[0:5])),\n",
    "        ', '.join(map(str, candidate.Genes[5:10])),\n",
    "        candidate.Fitness,\n",
    "        timeDiff))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Chromosome:\n",
    "    def __init__(self, genes, fitness):\n",
    "        self.Genes = genes\n",
    "        self.Fitness = fitness"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 90,
   "metadata": {},
   "outputs": [],
   "source": [
    "def mutate(parent, geneset):\n",
    "    genes = parent.Genes[:]\n",
    "    for i in range(4):\n",
    "        indexA, indexB = random.sample(range(len(genes)), 2)\n",
    "        genes[indexA], genes[indexB] = genes[indexB], genes[indexA]\n",
    "    fitness = get_fitness(genes)\n",
    "    return Chromosome(genes, fitness)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 91,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_best():\n",
    "    startTime = datetime.datetime.now()\n",
    "    optimalFitness = Fitness(36, 360)\n",
    "    best = Chromosome(geneset, get_fitness(geneset))\n",
    "    if best.Fitness == optimalFitness:\n",
    "        return best\n",
    "    num = 0\n",
    "    while True:\n",
    "        num +=1\n",
    "        child = mutate(best,geneset)\n",
    "        if best.Fitness > child.Fitness:\n",
    "            continue\n",
    "        display(child,startTime)\n",
    "        if not child.Fitness > best.Fitness:\n",
    "            best = child\n",
    "        if child.Fitness == optimalFitness:\n",
    "            break\n",
    "        best = child\n",
    "    return (best,num)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 92,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "b= get_best()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 93,
   "metadata": {},
   "outputs": [],
   "source": [
    "n = []\n",
    "for i in range(100):\n",
    "    n.append(get_best()[1]) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 94,
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 95,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([32., 20., 11.,  9., 10.,  7.,  4.,  4.,  1.,  2.]),\n",
       " array([   4. ,  225.6,  447.2,  668.8,  890.4, 1112. , 1333.6, 1555.2,\n",
       "        1776.8, 1998.4, 2220. ]),\n",
       " <a list of 10 Patch objects>)"
      ]
     },
     "execution_count": 95,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.hist(n)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 96,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 97,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "585.51"
      ]
     },
     "execution_count": 97,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "numpy.mean(n)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
